package com.timk.goserver.server.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * Class for sending email messages
 * @author TKington
 *
 */
public class Mailman {
	private static final BlockingQueue queue;
	
	static {
		queue = new BlockingQueue();
		new SendThread(queue).start();
	}
	
	/**
	 * Sends an email message
	 * @param recipients List&lt;String&gt; of email addresses
	 * @param subject the subject
	 * @param message the message
	 * @param isHTML true if the content type should be text/html
	 */
	public static void sendMessage(List recipients, String subject,
			String message, boolean isHTML) {
		MessageInfo info = new MessageInfo(recipients, subject, message, isHTML);
		
		//	This will happen if all of the email addresses are invalid
		if(info.getRecipients().size() == 0) {
			return;
		}
		
		queue.put(info);
	}
	
	private static class SendThread extends Thread {
		private final BlockingQueue q;
		private Session session;
		
		/**
		 * Creates a SendThread
		 * @param queue
		 */
		public SendThread(BlockingQueue queue) {
			this.q = queue;
		}
		
		public void run() {
			init();
			
			MessageInfo msg;
			while(true) {				
				try {
					msg = (MessageInfo)q.get();
					sendMessage(msg);
				} catch (InterruptedException e) {
					GSLogger.logError("Interrupted while wating for MessageInfo", e);
				}
				
			}
		}
		
		private void init() {
			String host = GlobalProperties.getProperty("smtp.host");
			String port = GlobalProperties.getProperty("smtp.port");
			String user = GlobalProperties.getProperty("smtp.user");
			String pass = GlobalProperties.getProperty("smtp.pass");
			
			Properties props = new Properties();
			props.put("mail.transport.protocol", "smtp");
			props.put("mail.smtp.host", host);
			props.setProperty("mail.smtp.socketFactory.class",
					"javax.net.ssl.SSLSocketFactory");
			props.put("mail.smtp.port", port);
			props.put("mail.smtp.auth", "true");

			Authenticator auth = new SMTPAuthenticator(user, pass);
			session = Session.getDefaultInstance(props, auth);
			session.setDebug(false);
		}
		
		/**
		 * Sends an email message
		 * @param msgInfo the MessageInfo
		 */
		private void sendMessage(MessageInfo msgInfo) {
			try {
				// create a message
				Message msg = new MimeMessage(session);
		
				// set the from and to address
				InternetAddress addressFrom = new InternetAddress("noreply@noreply.com");
				msg.setFrom(addressFrom);
		
				List recipients = msgInfo.getRecipients();
				InternetAddress[] addressTo = new InternetAddress[recipients.size()];
				for (int i = 0; i < recipients.size(); i++) {
					addressTo[i] = (InternetAddress)recipients.get(i);
				}
				msg.setRecipients(Message.RecipientType.TO, addressTo);
		
				// Setting the Subject and Content Type
				msg.setSubject(msgInfo.getSubject());
				
				if(msgInfo.isHtml()) {
					msg.setContent(msgInfo.getBody(), "text/html");
				} else {
					msg.setContent(msgInfo.getBody(), "text/plain");
				}
		
				Transport.send(msg);
			} catch(Exception e) {
				GSLogger.logError("Error sending email", e);
			}
		}
	}

	private static class MessageInfo {
		private final List recipients;
		private final String subject;
		private final String body;
		private final boolean html;
		
		/**
		 * Creates a MessageInfo
		 * @param recipients List&lt;String&gt; containing email addresses
		 * @param subject
		 * @param body
		 * @param isHTML true if the content type should be text/html
		 */
		public MessageInfo(List recipients, String subject,
				String body, boolean isHTML) {
			this.subject = subject;
			this.body = body;
			this.html = isHTML;
			
			this.recipients = new ArrayList();
			for (Iterator iter = recipients.iterator(); iter.hasNext();) {
				try {
					InternetAddress addr = new InternetAddress((String)iter.next());
					this.recipients.add(addr);
				} catch (AddressException e) {	// NOPMD - empty catch
					//	bad e-mail address, no big deal
				}
			}
		}

		/**
		 * Returns the body of the message
		 * @return the body of the message
		 */
		public String getBody() {
			return body;
		}

		/**
		 * Returns the list of recipients
		 * @return List&lt;String&gt; of email addresses
		 */
		public List getRecipients() {
			return recipients;
		}

		/**
		 * Returns the subject
		 * @return the subject
		 */
		public String getSubject() {
			return subject;
		}
		
		/**
		 * Returns true if the content type should be text/html
		 * @return true if the content type should be text/html
		 */
		public boolean isHtml() {
			return html;
		}
	}

	/**
	 * SimpleAuthenticator is used to do simple authentication when the SMTP
	 * server requires it.
	 */
	private static class SMTPAuthenticator extends javax.mail.Authenticator {
		private final String username;
		private final String password;
		
		SMTPAuthenticator(String username, String password) {
			this.username = username;
			this.password = password;
		}

		public PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(username, password);
		}
	}
}
